home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
501-525
/
disk_502
/
cells
/
cellssource.lzh
/
cError.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-20
|
11KB
|
426 lines
/*
* CELLS An Implementation of the WireWorld cellular automata
* as described in Scientific American, Jan 1990.
*
* Copyright 1990 by Davide P. Cervone.
* You may use this code, provided this copyright notice is kept intact.
* See the CELLS.HELP file for complete information on distribution conditions.
*/
/*
* File: cError.c Handles error and info requesters.
* Also handles safe memory allocation.
*/
#include "Cells.h"
#include "cError.h"
#include "cBoxes.h"
#include <libraries/dosextens.h>
extern struct IntuiMessage *GetMsg();
extern int DelayedShift;
#define MEM_DANGER (16*1024) /* when to really get mad */
#define MEM_WARNING (32*1024) /* when to warn about low memory */
#define MEM_OK (MEM_WARNING+1) /* memory OK over this amount */
static int ErrorLevel = MEM_OK; /* current memory warning level */
static char *SavedTitle; /* saved screen title */
static int InfoReqActive; /* TRUE if INFO message up */
static APTR OldPrWindow; /* old process window pointer */
static struct Process *ourProcess; /* the CELLS process */
/*
* The strucutres for the Error, Info, and Question requesters
*/
static short PanelBox[] = FBOX(ER_PANELW,ER_PANELH);
static short FrameBox[] = FBOX(ER_FRAMEW,ER_FRAMEH);
static short ButtonBox[] = FBOX(ER_BUTTONW,ER_BUTTONH);
static struct Border ERBorder[] =
{
#define NEXTBORDER(n) &ERBorder[n+2]
#define BORDERNAME ERBorder
OUTBRDR(ERB_PANEL, 0,0, PanelBox),
#undef NEXTBORDER
#define NEXTBORDER(n) NULL
INBRDR (ERB_FRAME, ER_FRAMEX,ER_FRAMEY, FrameBox),
OUTBRDR(ERB_BUTTON, 0,0, ButtonBox)
};
static struct IntuiText ERText[] =
{
ITEXT("OK", 7,3),
{ERRORPEN,FOREGROUND,JAM2, ER_TITLEX,ER_TITLEY,
NULL, NULL, &ERText[ERT_MESS1]},
ITEXT(NULL, 0,ER_MESS1Y),
ITEXT(NULL, 0,ER_MESS2Y),
ITEXT("Yes", 3,3),
ITEXT("No", 7,3),
};
static struct Gadget ERGadget[] =
{
{NULL, ER_BUTTONX,ER_BUTTONY, ER_BUTTONW,ER_BUTTONH, GADGHCOMP,
RELVERIFY, BOOLGADGET|REQGADGET, (APTR)&ERBorder[ERB_BUTTON],
NULL, &ERText[ERT_OK], 0, NULL, ER_OK, NULL},
{&ERGadget[2], ER_BUTTONX,ER_BUTTONY, ER_BUTTONW,ER_BUTTONH, GADGHCOMP,
RELVERIFY, BOOLGADGET|REQGADGET, (APTR)&ERBorder[ERB_BUTTON],
NULL, &ERText[ERT_YES], 0, NULL, ER_YES, NULL},
{NULL, ER_BUTTONX-ER_BUTTONW,ER_BUTTONY, ER_BUTTONW,ER_BUTTONH, GADGHCOMP,
RELVERIFY, BOOLGADGET|REQGADGET, (APTR)&ERBorder[ERB_BUTTON],
NULL, &ERText[ERT_NO], 0, NULL, ER_NO, NULL},
};
static struct Requester ERRequest =
{
NULL, (BOARDW-ER_PANELW)/2,(BOARDH-ER_PANELH)/2, ER_PANELW,ER_PANELH,
0,0, &ERGadget[0], &ERBorder[ERB_PANEL], &ERText[ERT_TITLE], 0, FOREGROUND,
NULL, NULL, NULL
};
/*
* SetErrorText()
*
* Set the requesters title and message strings.
* Break a long message string into two parts (at a space), center the
* two parts horizontally and make them look good vertically.
* Center single line message properly
*/
static void SetErrorText(Title,Message)
char *Title;
char *Message;
{
register short i;
short Len = strlen(Message);
ERText[ERT_TITLE].IText = Title;
ERText[ERT_MESS1].IText = Message;
if (Len > 30)
{
ERText[ERT_MESS1].NextText = &ERText[ERT_MESS2];
ERText[ERT_MESS1].TopEdge = ER_MESS1Y;
ERText[ERT_MESS2].TopEdge = ER_MESS2Y;
for (i=30; i>0 && Message[i] != ' '; i--);
if (i == 0) i = 30;
Message[i++] = 0;
ERText[ERT_MESS1].LeftEdge = (ER_PANELW - CHAR_WIDTH*(i-1)) / 2;
ERText[ERT_MESS2].LeftEdge = (ER_PANELW - CHAR_WIDTH*(Len-i)) / 2;
ERText[ERT_MESS2].IText = &Message[i];
} else {
ERText[ERT_MESS1].LeftEdge = (ER_PANELW - CHAR_WIDTH*Len) / 2;
ERText[ERT_MESS1].TopEdge = ER_MESSY;
ERText[ERT_MESS1].NextText = NULL;
}
}
/*
* WaitForGadget()
*
* As long as no gadget is pressed
* For each message in the window's UserPort,
* store the delayed shift,
* if the message is a gadget up,
* do the Gadget routine with the given gadget
* reply to the message
* If we are not yet done, wait for additional messages
*/
static void WaitForGadget(DoGadget)
int (*DoGadget)();
{
struct IntuiMessage *theMessage;
short NotDone = TRUE;
struct MsgPort *thePort = myWindow->UserPort;
long SignalMask = (1 << thePort->mp_SigBit);
while (NotDone)
{
while (theMessage = GetMsg(thePort))
{
DelayedShift = theMessage->Qualifier & SHIFTKEYS;
if (theMessage->Class == GADGETUP)
NotDone = (*DoGadget)(theMessage->IAddress,NotDone);
ReplyMsg(theMessage);
}
if (NotDone) Wait(SignalMask);
}
}
/*
* ClearInfoMessage()
*
* If the Info requester is up, remove the requester and clear the flag.
*/
void ClearInfoMessage()
{
if (InfoReqActive)
{
EndRequest(&ERRequest,myWindow);
InfoReqActive = FALSE;
}
}
/*
* DoInfoMessage()
*
* Clear any previous info message,
* Set the message and title strings, and remove the requester's gadgets
* Put up the requester, if possible.
*/
void DoInfoMessage(s,x1,x2,x3)
char *s,*x1,*x2,*x3;
{
static char Message[80];
ClearInfoMessage();
sprintf(Message,s,x1,x2,x3);
SetErrorText("Please Be Patient:",Message);
ERRequest.ReqGadget = NULL;
if (Request(&ERRequest,myWindow)) InfoReqActive = TRUE;
}
/*
* CheckForOK
*
* If the gadget ID is the OK gadget, then we're done
*/
static int CheckForOK(theGadget,NotDone)
struct Gadget *theGadget;
int NotDone;
{
if (theGadget->GadgetID == ER_OK) NotDone = FALSE;
return(NotDone);
}
/*
* DoError()
*
* Clear the info requester if it is up
* Prepare the error message, and set the requester title and gadgets
* Put up the requester, if possible.
* If not, try to free HELP information and try again.
* If the requester could be openned,
* wait for the OK button to be pressed, and then end the requester
* Otherwise
* Remake the error message in case it was divied into two lines.
* put the message into the screen title and save the old title.
*/
void DoError(s,x1,x2,x3)
char *s,*x1,*x2,*x3;
{
char Message[80];
int ReqSet;
ClearInfoMessage();
sprintf(Message,s,x1,x2,x3);
SetErrorText("Error Report:",Message);
ERRequest.ReqGadget = &ERGadget[0];
ReqSet = Request(&ERRequest,myWindow);
if (!ReqSet)
{
if (CanClearHelpLines()) ReqSet = Request(&ERRequest,myWindow);
if (!ReqSet && CanClearHelpTopics())
ReqSet = Request(&ERRequest,myWindow);
}
if (ReqSet)
{
WaitForGadget(&CheckForOK);
EndRequest(&ERRequest,myWindow);
} else {
sprintf(Message,s,x1,x2,x3);
if (SavedTitle == NULL) SavedTitle = myWindow->ScreenTitle;
SetWindowTitles(myWindow,-1,Message);
}
}
/*
* ClearError()
*
* If the message was a mouse button, gadget up or down, or a window
* inactivation event, and we had previously saved a window title,
* put back the old title, and clear the saved title.
*/
void ClearError(theMessage)
struct IntuiMessage *theMessage;
{
switch (theMessage->Class)
{
case MOUSEBUTTONS:
case GADGETUP:
case GADGETDOWN:
case INACTIVEWINDOW:
if (SavedTitle) SetWindowTitles(myWindow,-1,SavedTitle);
SavedTitle = NULL;
break;
}
}
static int YesOrNo;
/*
* CheckForYesNo()
*
* If either button is pressed, we're done. Record the correct YesOrNo
* value for a YES being pressed.
*/
static int CheckForYesNo(theGadget,NotDone)
struct Gadget *theGadget;
int NotDone;
{
switch(theGadget->GadgetID)
{
case ER_YES:
YesOrNo = TRUE;
case ER_NO:
NotDone = FALSE;
break;
}
return(NotDone);
}
/*
* DoQuestion()
*
* Clear the info requester, if any is up.
* set the requester title and message strings, and set up the gadget list.
* Clear the YesOrNo answer.
* Put up the requester, if possible.
* If successful, wait for the Yes or No buttons to be pressed
* and then remove the requester
* return the button that was pressed.
*/
int DoQuestion(s,x1,x2,x3)
char *s,*x1,*x2,*x3;
{
char Message[80];
ClearInfoMessage();
sprintf(Message,s,x1,x2,x3);
SetErrorText("Confirmation Requested:",Message);
ERRequest.ReqGadget = &ERGadget[1];
YesOrNo = FALSE;
if (Request(&ERRequest,myWindow))
{
WaitForGadget(&CheckForYesNo);
EndRequest(&ERRequest,myWindow);
}
return(YesOrNo);
}
#undef AllocMem
static int BufferErrors,ErrorReported;
/*
* myAllocMem()
*
* Attempt to allocate the requested block of memory.
* Check the remaining memory available.
* If there is little memory left, or if there was not enough to get the
* requested chunk,
* Try to clear the help text lines that aren't in use, and try
* to allocate the memory again, if necessary.
* If there's still very little memory,
* Try to free the help topics as well, and then try to get the
* memory again, if necessary.
* If there is a dangerously small amount of memory,
* and we haven't already said so, then give a memory warning, and
* record that we did so.
* Otherwise, if there is little memory left,
* and we haven't already mentioned it, do so and record that we did.
* Otherwise, note that there is sufficient memory again.
*/
APTR myAllocMem(n,Flags)
int n;
ULONG Flags;
{
long Mem;
APTR theByte;
extern APTR AllocMem();
extern long AvailMem();
theByte = AllocMem(n,Flags);
Mem = AvailMem(0);
if (Mem < MEM_WARNING || theByte == NULL)
{
if (CanClearHelpLines())
{
if (theByte == NULL) theByte = AllocMem(n,Flags);
Mem = AvailMem(0);
}
if (Mem < MEM_DANGER || theByte == NULL)
{
if (CanClearHelpTopics())
{
if (theByte == NULL) theByte = AllocMem(n,Flags);
Mem = AvailMem(0);
}
}
}
if (Mem < MEM_DANGER)
{
if (ErrorLevel > MEM_DANGER)
DoError("Danger: Only %dK Memory Free!",Mem/1024);
ErrorLevel = MEM_DANGER;
} else if (Mem < MEM_WARNING) {
if (ErrorLevel > MEM_WARNING)
DoError("Low On Memory: %dK Remaining",Mem/1024);
ErrorLevel = MEM_WARNING;
} else {
ErrorLevel = MEM_OK;
}
return(theByte);
}
/*
* SetErrorWindow()
*
* Set the process error screen to be the CELLS screen, but record the
* old window pointer so we can replace it later.
*/
void SetErrorWindow(theWindow)
APTR theWindow;
{
extern struct Process *FindTask();
ourProcess = FindTask(NULL);
OldPrWindow = ourProcess->pr_WindowPtr;
ourProcess->pr_WindowPtr = theWindow;
}
/*
* ResetErrorWindow()
*
* Put back the old process error screen pointer, if we changed it above.
*/
void ResetErrorWindow()
{
if (ourProcess) ourProcess->pr_WindowPtr = OldPrWindow;
}